home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-06-30 | 12.2 KB | 275 lines | [TEXT/R*ch] |
- // This may look like C code, but it is really -*- C++ -*-
- /*
- ************************************************************************
- *
- * Grayscale Image
- *
- * Write an image into a file in the TIFF format
- *
- * The present TIFF writer creates a Class G TIFF file (for gray-scale
- * images), See Appendix G of the TIFF specification.
- *
- * The program writes the following required tags
- * NewSubfileType
- * ImageWidth
- * ImageLength
- * RowsPerStrip (To make strips around 8K)
- * StripOffsets
- * Strip ile) {} // Value is a part of the item, and
- // is written along with the item
-
- public:
- ScalarTIFFDE(const short _tag, const SHORT _value)
- : TIFFDirectoryItem(_tag,SHORT,1,(unsigned long)_value << 16) {}
- ScalarTIFFDE(const short _tag, const LONG _value)
- : TIFFDirectoryItem(_tag,LONG,1,_value) {}
- ~ScalarTIFFDE(void) {}
- };
-
- // Write this item into a file
- void ScalarTIFFDE::write(EndianIO& file)
- {
- file.write_short(tag);
- file.write_short(type);
- file.write_long(count);
- file.write_long(val_offset);
- }
-
-
- // String item, the string itself is written
- // after the IFD, the val_offset field of
- // the item stores an offset to the string
- // characters.
- class StringTIFFDE : public TIFFDirectoryItem
- {
- protected:
- void write(EndianIO& file); // Write this field into a file
- void write_value(EndianIO& file); // Write the body of the string
- // (after the directory is written)
-
- long int offset_for_val; // for the val_offset field
-
- public:
- StringTIFFDE(const short _tag, const char * str)
- : TIFFDirectoryItem(_tag,ASCII, str == 0 || str[0] == '\0' ? //empty string
- 0 : strlen(str)+1,(long)str) {}
- ~StringTIFFDE(void) {}
- };
-
- // Write this item into a file
- void StringTIFFDE::write(EndianIO& file)
- {
- assert( count > 0 );
- file.write_short(tag);
- file.write_short(type);
- file.write_long(count);
- offset_for_val = file.tellp();
- file.write_long(0); // write a dummy for now
- }
-
- // Write the body of the string,
- // Note, a padding may be necessary to
- // make the string end at a word boundary
- void StringTIFFDE::write_value(EndianIO& file)
- {
- long int pos = file.tellp(); // where are we now
- // Write a body of the string, '\0'
- // and (possible) an extra byte
- file.write((char *)val_offset,(strlen((char *)val_offset)+1+1) & ~1);
- // to keep word-boundary align
- long int pos_new = file.tellp();
- assert( file.seekp(offset_for_val).good() );
- file.write_long(pos); // Write the offset within the dir elem
- assert( file.seekp(pos_new).good() ); // Restore the file position
- // to continue writing
- }
-
-
- // Directory item that refers to an array
- // (that can contain strip offsets, strip
- // byte counts, or other info specific to
- // each strip)
- class ArrayTIFFDE : public TIFFDirectoryItem
- {
- protected:
- virtual void write(EndianIO& file); // Write this field into a file
- virtual void write_value(EndianIO& file); // Write the body of the array
- // (after the directory is written)
-
- long int offset_for_val; // for the val_offset field
- long * array;
-
- public:
- ArrayTIFFDE(const short _tag, const long no_elems);
- ~ArrayTIFFDE(void);
- long& operator [] (const int index) // Get hold of an element of the array
- { assert( index >= 0 && index < count ); return array[index]; }
- };
-
- // Constructor - allocate the array
- ArrayTIFFDE::ArrayTIFFDE(const short _tag, const long no_elems)
- : TIFFDirectoryItem(_tag, LONG, no_elems, 0)
- {
- assert( count > 0 );
- array = new long[count];
- }
-
-
- // Dispose of the array
- ArrayTIFFDE::~ArrayTIFFDE(void)
- {
- assert( array != 0 );
- delete array;
- array = 0;
- }
-
-
- // Write this item into a file
- void ArrayTIFFDE::write(EndianIO& file)
- {
- assert( count > 0 );
- file.write_short(tag);
- file.write_short(type);
- file.write_long(count);
- offset_for_val = file.tellp();
- file.write_long(0); // write a dummy for now
- }
-
- // Write array elements (if more than 1)
- // after the directory
- void ArrayTIFFDE::write_value(EndianIO& file)
- {
- long int pos; // Where the array is to be written
- register int i;
- if( count == 1 ) // If there is only one elem, keep
- pos = array[0]; // the offset with the dir elem itself
- else
- {
- pos = file.tellp(); // Write the array separately
- for(i=0; i<count; i++)
- file.write_long(array[i]);
- }
- long int pos_new = file.tellp();
- assert( offset_for_val > 0 && file.seekp(offset_for_val).good() );
- file.write_long(pos); // Write the offset within the dir elem
- assert( file.seekp(pos_new).good() ); // Restore the file position
- // to continue writing
- }
-
- // Rational number: an array of two LONGs
- class RationalTIFFDE : public ArrayTIFFDE
- {
- virtual void write(EndianIO& file); // Write this field into a file
- public:
- RationalTIFFDE(const short _tag, const int numerator,const int denominator)
- : ArrayTIFFDE(_tag,2)
- { array[0] = numerator; array[1] = denominator; type = RATIONAL; }
- };
-
- // Write this item into a file: only one
- // modification: a rational has count 1, though
- // it's an array of 2 longs
- void RationalTIFFDE::write(EndianIO& file)
- {
- assert( count == 2 );
- count = 1; // temporarily: that's what we write
- ArrayTIFFDE::write(file); // into the tag
- count = 2;
- }
-
-
- // Strip item, that refers to an array
- // that contains offsets to the strips (set
- // of rows) of the image
- // No compression is used at present
- class StripTIFFDE : public ArrayTIFFDE
- {
- protected:
- void write_value(EndianIO& file); // Write the array of strip ptrs
- // and strips themselves
- // (after the directory is written)
-
- ArrayTIFFDE strip_byte_counts; // It is not necessary unless compress-
- // ion is used; but neverthelesss
- short rows_per_strip;
- const IMAGE& image;
-
- public:
- StripTIFFDE(const short _no_strips, const short _rows_per_strip,
- const IMAGE& _image)
- : ArrayTIFFDE(TIFFTAG_STRIPOFFSETS,_no_strips),
- strip_byte_counts(TIFFTAG_STRIPBYTECOUNTS,_no_strips),
- rows_per_strip(_rows_per_strip), image(_image) {}
- ~StripTIFFDE(void) {}
- };
-
- // Write the array of strip ptrs
- // and strips themselves
- // (after the directory is written)
- // Note the trick! StripByteCount
- // has a bigger tag, i.e. strip_byte_
- // count will be written AFTER the
- // strips are written, i.e., when
- // strip sizes are already known
- void StripTIFFDE::write_value(EndianIO& file)
- {
- assert( count > 0 );
- register int strip;
- for(strip=0; strip<count; strip++)
- {
- array[strip] = file.tellp(); // where are we now, beg of a strip
- register int i,j; // Writing a strip
- for(i=strip*rows_per_strip;
- i<(strip+1)*rows_per_strip && i < image.q_nrows(); i++)
- for(j=0; j<image.q_ncols(); j++)
- file.write_byte(image(i,j));
- strip_byte_counts[strip] = file.tellp() - array[strip];
- }
- ArrayTIFFDE::write_value(file);
- }
-
- /*
- *------------------------------------------------------------------------
- * Root module
- */
-
- void IMAGE::write_tiff(const char * file_name,const char * title) const
- {
- is_valid();
-
- message("\nPreparing a TIFF file with name '%s'\n",file_name);
-
- EndianIO file(file_name,ios::out);
-
- TIFFHeader header;
- header.write(file);
-
- ScalarTIFFDE subfile_tag(TIFFTAG_SUBFILETYPE,(long)0);
- ScalarTIFFDE width_tag(TIFFTAG_IMAGEWIDTH,q_ncols());
- ScalarTIFFDE length_tag(TIFFTAG_IMAGELENGTH,q_nrows());
- ScalarTIFFDE compr_tag(TIFFTAG_COMPRESSION,(short)COMPRESSION_NONE);
- ScalarTIFFDE phot_tag(TIFFTAG_PHOTOMETRIC,(short)PHOTOMETRIC_MINISBLACK);
- ScalarTIFFDE resunit_tag(TIFFTAG_RESOLUTIONUNIT,(short)RESUNIT_INCH);
- // Means 72 pixels per unit (inch)
- RationalTIFFDE xres_tag(TIFFTAG_XRESOLUTION,72,1);
- RationalTIFFDE yres_tag(TIFFTAG_YRESOLUTION,72,1);
-
- ScalarTIFFDE samplesize_tag(TIFFTAG_SAMPLESPERPIXEL,(short)1);
- assert( bits_per_pixel == 8 );
- ScalarTIFFDE depth_tag(TIFFTAG_BITSPERSAMPLE,(short)8);
-
-
- StringTIFFDE desc_tag(TIFFTAG_IMAGEDESCRIPTION, name );
- StringTIFFDE docname_tag(TIFFTAG_DOCUMENTNAME, title );
-
- const int strip_target_size = 8*1024;
- int rows_per_strip = strip_target_size / q_ncols();
- int no_strips = (q_nrows() + rows_per_strip - 1)/rows_per_strip;
- ScalarTIFFDE striprs_tag(TIFFTAG_ROWSPERSTRIP,(long)rows_per_strip);
- StripTIFFDE stripoffs_tag(no_strips, rows_per_strip, *this);
-
- subfile_tag.write_all(file);
- file.close();
- }
-
-